package com.a1anwang.okble.client.scan;

import com.a1anwang.okble.common.OKBLEDataUtils;
import ohos.bluetooth.BluetoothRemoteDevice;
import ohos.utils.Parcel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by a1anwang.com on 2017/6/26.
 * contact：www.a1anwang.com
 */

public class BLEScanResult {
    private static final int DATA_TYPE_FLAGS = 0x01;
    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
    private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
    private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
    private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
    private static final int DATA_TYPE_SERVICE_DATA = 0x16;
    private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
    private BluetoothRemoteDevice bluetoothDevice;
    private byte[] advertisingData;
    private int rssi;
    private int txPowerLevel = Integer.MIN_VALUE;
    private List<String> serviceUuids;
    private HashMap<Integer, byte[]> manufacturerSpecificData;
    private String completeLocalName;
    private Map<String, byte[]> serviceData;

    /**
     * 构造函数
     */
    public BLEScanResult() {
    }

    /**
     * 构造函数
     *
     * @param in Parcel对象
     */
    protected BLEScanResult(Parcel in) {
        bluetoothDevice = in.createSequenceable(BluetoothRemoteDevice.class.getClassLoader());
        advertisingData = in.readByteArray();

        rssi = in.readInt();
        txPowerLevel = in.readInt();
        serviceUuids = in.readStringList();
        serviceUuids = in.readStringList();
        completeLocalName = in.readString();
    }

    /**
     * 获取mac地址
     *
     * @return string
     */
    public String getMacAddress() {
        if (bluetoothDevice != null) {
            return bluetoothDevice.getDeviceAddr();
        }
        return null;
    }

    public String getCompleteLocalName() {
        return completeLocalName;
    }

    public int getRssi() {
        return rssi;
    }

    /**
     * 构造函数
     *
     * @param bluetoothDevice 蓝牙远端设备
     * @param advertisingData 数据
     * @param rssi            rssi
     */
    public BLEScanResult(BluetoothRemoteDevice bluetoothDevice, byte[] advertisingData, int rssi) {
        this.bluetoothDevice = bluetoothDevice;
        this.advertisingData = advertisingData.clone();

        this.rssi = rssi;
        analyzeAdvertisingData();

    }

    public byte[] getAdvertisingData() {
        byte[] advertisingData = this.advertisingData;
        return advertisingData;
    }

    public int getTxPowerLevel() {
        return txPowerLevel;
    }

    public BluetoothRemoteDevice getBluetoothDevice() {
        BluetoothRemoteDevice bluetoothDevice = this.bluetoothDevice;
        return bluetoothDevice;
    }

    /**
     * 获取uuid列表
     *
     * @return List<String>
     */
    public synchronized List<String> getServiceUuids() {
        if (serviceUuids == null) {
            analyzeAdvertisingData();
        }
        List<String> serviceUuids = this.serviceUuids;
        return serviceUuids;
    }

    /**
     * getManufacturerSpecificData
     *
     * @return HashMap<Integer, byte[]>
     */
    public synchronized HashMap<Integer, byte[]> getManufacturerSpecificData() {
        if (manufacturerSpecificData == null) {
            analyzeAdvertisingData();
        }
        return manufacturerSpecificData;
    }

    /**
     * getServiceData
     *
     * @return Map<String, byte[]>
     */
    public synchronized Map<String, byte[]> getServiceData() {
        if (serviceData == null) {
            analyzeAdvertisingData();
        }
        return serviceData;
    }

    private synchronized void analyzeAdvertisingData() {
        if (advertisingData != null && advertisingData.length > 0) {
            int index = 0;
            while (index < advertisingData.length - 1) {
                int length = advertisingData[index];
                if (length == 0) {
                    break;
                }
                int type = advertisingData[index + 1];
                if (type == (byte) DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL) {
                    if (serviceUuids == null) {
                        serviceUuids = new ArrayList<>();
                    }
                    byte[] serveruuids = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    if (serveruuids.length % 2 == 0) {
                        int count = serveruuids.length / 2;
                        for (int i = 0; i < count; i++) {
                            byte[] serveruuid = new byte[]{serveruuids[2 * i + 1], serveruuids[2 * i]};
                            String uuid = OKBLEDataUtils.BytesToHexString(serveruuid);
                            serviceUuids.add(uuid);
                        }
                    }
                } else if (type == (byte) DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE) {
                    if (serviceUuids == null) {
                        serviceUuids = new ArrayList<>();
                    }
                    byte[] serveruuids = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    if (serveruuids.length % 2 == 0) {
                        int count = serveruuids.length / 2;
                        for (int i = 0; i < count; i++) {
                            byte[] serveruuid = new byte[]{serveruuids[2 * i + 1], serveruuids[2 * i]};
                            String uuid = OKBLEDataUtils.BytesToHexString(serveruuid);
                            serviceUuids.add(uuid);
                        }
                    }
                } else if (type == (byte) DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL) {
                    if (serviceUuids == null) {
                        serviceUuids = new ArrayList<>();
                    }
                    byte[] serveruuids = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    if (serveruuids.length % 16 == 0) {
                        int count = serveruuids.length / 16;
                        for (int ii = 0; ii < count; ii++) {
                            byte[] serveruuid = new byte[16];
                            for (int j = 0; j < 16; j++) {
                                serveruuid[j] = serveruuids[16 * ii + (15 - j)];
                            }
                            String hexStr = OKBLEDataUtils.BytesToHexString(serveruuid);
                            String uuid = hexStr.substring(0, 8);
                            uuid += "-";
                            uuid += hexStr.substring(8, 12);
                            uuid += "-";
                            uuid += hexStr.substring(12, 16);
                            uuid += "-";
                            uuid += hexStr.substring(16, 20);
                            uuid += "-";
                            uuid += hexStr.substring(20, 32);
                            serviceUuids.add(uuid);
                        }
                    }
                } else if (type == (byte) DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE) {
                    if (serviceUuids == null) {
                        serviceUuids = new ArrayList<>();
                    }
                    byte[] serveruuids = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    if (serveruuids.length % 16 == 0) {
                        int count = serveruuids.length / 16;
                        for (int i2 = 0; i2 < count; i2++) {
                            byte[] serveruuid = new byte[16];
                            for (int j = 0; j < 16; j++) {
                                serveruuid[j] = serveruuids[16 * i2 + (15 - j)];
                            }
                            String hexStr = OKBLEDataUtils.BytesToHexString(serveruuid);
                            String uuid = hexStr.substring(0, 8);
                            uuid += "-";
                            uuid += hexStr.substring(8, 12);
                            uuid += "-";
                            uuid += hexStr.substring(12, 16);
                            uuid += "-";
                            uuid += hexStr.substring(16, 20);
                            uuid += "-";
                            uuid += hexStr.substring(20, 32);
                            serviceUuids.add(uuid);
                        }
                    }
                } else if (type == (byte) DATA_TYPE_SERVICE_DATA) {
                    serviceData = new HashMap<>();
                    byte[] serverData = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    byte[] uuid = new byte[]{serverData[1], serverData[0]};
                    byte[] data = OKBLEDataUtils.subByteArray(serverData, 2, serverData.length - 2);
                    String uuidStr = OKBLEDataUtils.BytesToHexString(uuid);
                    serviceData.put(uuidStr, data);
                } else if (type == (byte) DATA_TYPE_MANUFACTURER_SPECIFIC_DATA) {
                    manufacturerSpecificData = new HashMap<>();
                    byte[] manufacturerData = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    byte[] manufacturerId = new byte[]{manufacturerData[1], manufacturerData[0]};
                    byte[] manufacturerValue = OKBLEDataUtils.subByteArray(manufacturerData, 2, manufacturerData.length - 2);
                    manufacturerSpecificData.put(OKBLEDataUtils.buildUint16(manufacturerId[0], manufacturerId[1]), manufacturerValue);
                } else if (type == (byte) DATA_TYPE_LOCAL_NAME_COMPLETE) {
                    byte[] nameData = OKBLEDataUtils.subByteArray(advertisingData, index + 2, length - 1);
                    completeLocalName = new String(nameData);
                } else if (type == (byte) DATA_TYPE_TX_POWER_LEVEL) {
                    txPowerLevel = advertisingData[index + 2];
                }

                //1是length自身占一个字节
                index += length + 1;
            }
        }
    }

    @Override
    public String toString() {
        return "[ScanResult:" + " mac:" + getMacAddress() + " name:" + getBluetoothDevice().getDeviceName() + "]";
    }
}

